30. K-Means算法-股市波动聚类

本节内容概览

  • K-Means算法是经典的无监督聚类方法
  • 核心思想:将数据自动分为K个组(簇)
  • 本节将其应用于股指波动数据的分类

什么是无监督学习?

  • 监督学习:数据有标签(如”涨”或”跌”)
  • 无监督学习:数据没有标签,让算法自行发现结构
  • K-Means 就是一种典型的无监督学习方法

K-Means算法的目标

最小化簇内平方和(SSE)

\[SSE = \sum_{i=1}^{K}\sum_{x \in C_i} ||x - \mu_i||^2\]

  • \(K\):簇的数量
  • \(C_i\):第 \(i\) 个簇中的所有数据点
  • \(\mu_i\):第 \(i\) 个簇的质心(均值中心)

K-Means算法四步流程

  1. 随机初始化 K 个质心
  2. 分配样本:将每个数据点归入最近的质心
  3. 更新质心:重新计算每个簇的均值
  4. 重复步骤 2-3,直到质心不再变化(收敛)

K-Means迭代过程示意

K-Means迭代四步流程 展示K-Means算法从初始化质心到收敛的四个步骤。 Step 1 随机初始化 K个质心 Step 2 分配每个样本 到最近质心 Step 3 重新计算 每个簇的质心 Step 4 收敛? 否则回到Step2 未收敛则重复迭代

如何确定K值?——肘部法则

  • 依次尝试 \(K=1,2,\dots,9\),计算每个K的SSE
  • 绘制SSE随K变化的折线图
  • 拐点(“肘部”)对应的K即为最优簇数

⭐ 平台任务:肘部法则与K-Means聚类

Listing 1
# 注:case3.1.xlsx数据文件本地没有,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库
from sklearn.cluster import KMeans  # 导入Scikit-learn的KMeans模块
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
data = pd.read_excel("case3.1.xlsx")  # 从Excel文件读取数据存入data
SSE = []  # 定义列表SSE
cols = data.iloc[:, 2:]  # 提取数值型特征列(跳过前两列的非数值信息)
for k in range(1,10):  # 遍历range(1,10)中的每个k
  estimator = KMeans(n_clusters=k)  # 初始化K-Means聚类模型
    estimator.fit(cols)  # 在数据上训练estimator模型
    SSE.append(estimator.inertia_)  # 将当前K值的簇内误差平方和(SSE)添加到列表
plt.plot(range(1,10), SSE,'*-')  # 绑制折线图
plt.title('Elbow Method')  # 设置图表标题
plt.xlabel('K Clusters')  # 设置X轴标签
plt.ylabel('SSE')  # 设置Y轴标签
plt.savefig("1.png") #过程展示一
data1=data.drop('股指',axis=1)  # 删除指定行或列
clu = KMeans(n_clusters=3,random_state=30)  # 初始化K-Means聚类模型
clu.fit(data1)  # 在数据上训练clu模型
label = clu.labels_  # 获取聚类模型对每个样本的簇标签
print(label)# 结果展示

平台代码解读:肘部法则部分

  • data.iloc[:, 2:]:提取第3列起的所有数值特征
  • KMeans(n_clusters=k):创建K-Means模型
  • estimator.inertia_:获取当前K值下的SSE
  • 最终绘制SSE随K变化的折线图,找出拐点

平台代码解读:聚类执行部分

  • data.drop('股指', axis=1):删除非数值列
  • KMeans(n_clusters=3, random_state=30):设定3个簇
  • clu.labels_:获取每个股指的聚类标签
  • 输出标签数组,查看每个股指属于哪一类

执行聚类分析详解

Listing 2
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行

# ==================== 准备聚类特征数据 ====================
data_features = data.drop('股指', axis=1)  # 删除非数值列'股指',axis=1表示按列删除
# 只保留数值型特征用于聚类分析

# ==================== 执行K-Means聚类 ====================
kmeans = KMeans(n_clusters=3, random_state=30)  # 创建K-Means模型,设置聚类数为3
# random_state=30设置随机种子,与之前不同会得到不同的初始质心
kmeans.fit(data_features)  # 在数据上拟合K-Means模型

# ==================== 获取聚类结果 ====================
labels = kmeans.labels_  # 获取每个样本的聚类标签(0, 1, 2)
# labels_属性存储了每个数据点所属的簇编号

# ==================== 获取聚类质心 ====================
centroids = kmeans.cluster_centers_  # 获取每个簇的质心坐标
# cluster_centers_属性存储了K个质心的位置

# ==================== 将聚类标签添加到原数据 ====================
data['Cluster'] = labels  # 在原数据中新增Cluster列,存储聚类结果
# 这样可以方便地按簇进行后续分析

print('聚类标签:')  # 输出标题
print(labels)  # 显示每个样本的聚类标签

print('\n各簇样本数:')  # 输出标题
print(pd.Series(labels).value_counts().sort_index())  # 统计每个簇的样本数
# pd.Series(labels).value_counts()统计每个标签出现的次数
# sort_index()按簇编号排序,使输出更清晰

print('\n聚类质心:')  # 输出标题
for i, centroid in enumerate(centroids):  # 遍历每个簇的质心
    print(f'\n{i}质心:')  # 输出簇编号
    for j, value in enumerate(centroid):  # 遍历质心的每个维度
        print(f'  特征{j+1}: {value:.4f}')  # 输出每个特征维度的质心坐标,保留4位小数

聚类执行代码要点

  • kmeans.labels_:每个样本的簇标签(0、1、2)
  • kmeans.cluster_centers_:每个簇的质心坐标
  • 将标签添加回原数据,便于后续分组分析

聚类结果可视化

Listing 3
# 注:该代码块依赖的数据来自上方平台任务代码块,因其未执行,本块也无法执行

# ==================== 按簇统计特征均值 ====================
cluster_stats = data.groupby('Cluster').mean()  # 按簇分组,计算各特征的平均值
print('各簇平均特征:')  # 输出标题
print(cluster_stats)  # 显示每个簇的特征均值
# 这有助于理解每个簇的特点和商业含义

# ==================== 可视化聚类结果 ====================
plt.figure(figsize=(10, 6))  # 创建10x6英寸的画布
scatter = plt.scatter(
    data_features.iloc[:, 0],  # x轴为第1个特征
    data_features.iloc[:, 1],  # y轴为第2个特征
    c=labels,  # 颜色由聚类标签决定
    cmap='viridis',  # 使用viridis配色方案
    s=100,  # 散点大小为100
    alpha=0.6  # 透明度为0.6
)
plt.colorbar(scatter, label='Cluster')  # 添加颜色条,显示簇编号
plt.scatter(
    centroids[:, 0],  # 质心的x坐标
    centroids[:, 1],  # 质心的y坐标
    c='red',  # 质心颜色为红色
    marker='X',  # 质心标记为X形
    s=300,  # 质心大小为300
    linewidths=2,  # 边框线宽为2
    edgecolors='black',  # 边框颜色为黑色
    label='质心'  # 图例标签
)
plt.title('K-Means聚类结果', fontsize=14)  # 设置图表标题
plt.xlabel('特征1', fontsize=12)  # 设置x轴标签
plt.ylabel('特征2', fontsize=12)  # 设置y轴标签
plt.legend()  # 显示图例
plt.grid(True, alpha=0.3)  # 显示网格线
plt.tight_layout()  # 自动调整布局
plt.show()  # 显示图表

可视化代码要点

  • plt.scatter(... c=labels ...):用聚类标签着色
  • 质心用红色 X 标记,便于识别每个簇的中心
  • plt.colorbar:添加颜色条,直观显示簇编号

金融领域的聚类应用场景

应用场景 说明
股票分类 根据波动率、收益率等特征分组
客户分层 作为RFM模型之外的补充手段
风险分组 识别高风险投资组合
异常检测 远离所有质心的数据点可能是异常

本节小结

  • K-Means是一种无监督学习方法,无需标签
  • 通过肘部法则确定最优K值
  • 核心流程:初始化 → 分配 → 更新 → 收敛
  • 在金融中广泛用于股票分类风险分组